package awesome.cpu.structure;

import awesome.cpu.utils.Mode;

public class RegisterFile extends SequentialComponent {
	
	private final static boolean outputDebug = true;
	
	private int mRegisters[] = new int[31]; 

	public final static int KEY_WRITE_ENABLE = 1;
	private int isWriteEnabled;
	
	public final static int KEY_READ_REG1 = 2;
	private int mReadReg1;
	public final static int KEY_READ_REG2 = 3;
	private int mReadReg2;
	public final static int KEY_READ_REG3 = 4;
	private int mReadReg3;
	public final static int KEY_WRITE_REG1 = 5;
	private int mWriteReg1;
	public final static int KEY_WRITE_REG2 = 6;
	private int mWriteReg2;
	public final static int KEY_WRITE_DATA1 = 7;
	private int mWriteData1;
	public final static int KEY_WRITE_DATA2 = 8;
	private int mWriteData2;
	
	public final static int KEY_READ_DATA1 = 9;
	//private int mReadData1;
	public final static int KEY_READ_DATA2 = 10;
	//private int mReadData2;
	public final static int KEY_READ_DATA3 = 11;
	//private int mReadData3;
	
	private final static RegisterFile mInstance = new RegisterFile();
	
	private RegisterFile() {
		for (int i = 0; i < 31; i ++)
			mRegisters[i] = i;
	}
	
	public static RegisterFile getInstance() {
		return mInstance;
	}
	
	@Override
	boolean setData(int keyInterface, int data) {
		switch (keyInterface) {
		case KEY_WRITE_ENABLE:
			isWriteEnabled = data;
			return true;
		case KEY_READ_REG1:
			mReadReg1 = data;
			return true;
		case KEY_READ_REG2:
			mReadReg2 = data;
			return true;
		case KEY_READ_REG3:
			mReadReg3 = data;
			return true;
		case KEY_WRITE_REG1:
			mWriteReg1 = data;
			return true;
		case KEY_WRITE_REG2:
			mWriteReg2 = data;
			return true;
		case KEY_WRITE_DATA1:
			mWriteData1 = data;
			return true;
		case KEY_WRITE_DATA2:
			mWriteData2 = data;
			return true;
		}
		return false;
	}
	
	@Override
	int getData(int keyInterface) {
		
		BusMonitor.transferData(InstructionRegister.getInstance(), 
				InstructionRegister.KEY_INSTRUCTION_23_19, 
				this, KEY_READ_REG1);
		BusMonitor.transferData(InstructionRegister.getInstance(),
				InstructionRegister.KEY_INSTRUCTION_4_0, 
				this, KEY_READ_REG2);
		BusMonitor.transferData(InstructionRegister.getInstance(),
				InstructionRegister.KEY_INSTRUCTION_18_14, 
				this, KEY_READ_REG3);
		
		switch (keyInterface) {
		case KEY_READ_DATA1:
			return readData1();
		case KEY_READ_DATA2:
			return readData2();
		case KEY_READ_DATA3:
			return readData3();
		}
		return 0;
	}
	
	private int readData1() {
		if (mReadReg1 <= 30 && mReadReg1 >= 0)
			return mRegisters[mReadReg1];
		return 0;
	}
	
	private int readData2() {
		if (mReadReg2 <= 30 && mReadReg2 >= 0)
			return mRegisters[mReadReg2];
		else return 0;
	}
	
	private int readData3() {
		if (mReadReg3 <= 30 && mReadReg3 >= 0)
			return mRegisters[mReadReg3];
		else return 0;
	}

	@Override
	void onClockTick() {
		switch (isWriteEnabled) {
		case 0: // write disabled
			break;
		case 1:	 // write 1 only
			mRegisters[mWriteReg1] = mWriteData1;
			if (outputDebug && Mode.getDebugLevel() >= Mode.DEBUG_LEVEL_PRINT_ALL) {
				System.out.println("RegFile: wrote reg["+mWriteReg1+"] = "+mWriteData1);
			}
			break;
		case 2:	 // write 1 and 2
			mRegisters[mWriteReg1] = mWriteData1;
			mRegisters[mWriteReg2] = mWriteData2;
			if (outputDebug && Mode.getDebugLevel() >= Mode.DEBUG_LEVEL_PRINT_ALL) {
				System.out.println("RegFile: wrote reg["+mWriteReg1+"] = "+mWriteData1);
				System.out.println("RegFile: wrote reg["+mWriteReg2+"] = "+mWriteData2);
			}
			break;
		}
		
		if (outputDebug && Mode.getDebugLevel() >= Mode.DEBUG_LEVEL_PRINT_ALL) {
			//System.out.println("RegFile: ReadReg1 = " + mReadReg1);
			//System.out.println("RegFile: ReadReg2 = " + mReadReg2);
			System.out.println("RegFile : WriteReg = " + isWriteEnabled);
			
		}
	}
}
